﻿using ArtMath.Attribute;
using ArtMath.Component.Interface;
using ArtMath.Component.Point;
using ArtMath.Converter;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using ArtMath.PointCollection;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using ArtMath.CommonType;

namespace ArtMath.Component.Circle
{
    /// <summary>
    /// 部分圆基类
    /// </summary>
    [Serializable]
    public abstract class PartialCircleBase : CircleLikeBase, IArc
    {
        PropertyDisplayer angleDisplayer, arclenDisplayer, chordlenDisplayer;

        public PartialCircleBase(SketchPad pad, string name, ToolTypeName toolType, bool addToList = true) : base(pad, name, toolType, addToList)
        {
            CentralAngleDisplayer = new PropertyDisplayer(this, "CentralAngle");
            ArcLengthDisplayer = new PropertyDisplayer(this, "ArcLength");
            ChordLengthDisplayer = new PropertyDisplayer(this, "ChordLength");
            ske = new PartialCircle() { Curves = new Curve[] { new Curve() } };
            pske = new PartialEllipse();
        }
        public override PointCollectionsManager NewSkeleton
        {
            get
            {
                Pad.BuildArcSamples(newCur, null, NewCenter, NewRadius, NewStart, NewSweep);
                return new PointCollectionsManager(new PartialCircle(NewCenter, NewRadius, NewStart, NewSweep) { Curves = new Curve[] { newCur } });
            }
        }
        public override PointCollectionsManager NewPSkeleton
        {
            get
            {
                Pad.BuildArcSamples(null, newPCur, NewCenter, NewRadius, NewStart, NewSweep);
                PartialEllipse e = new PartialEllipse() { Center = NewPCenter, Start = NewPStart, Sweep = NewPSweep, Curves = new Curve[] { newPCur } };
                double r = NewRadius;
                if (Pad.Coordinate == null)
                {
                    e.LongAxisHalfLength = e.ShortAxisHalfLength = r;
                }
                else
                {
                    e.LongAxisHalfLength = Pad.Coordinate.GetPx(r);
                    e.ShortAxisHalfLength = Pad.Coordinate.GetPy(r);
                }
                return new PointCollectionsManager(e);
            }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("ArcLength")]
        public double ArcLength { get; protected set; }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("ChordLength")]
        public double ChordLength { get; protected set; }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("CentralAngle"), TypeConverter(typeof(IntelliAngleConverter))]
        public double CentralAngle
        {
            get { return Math.Abs(Sweep); }
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName(null, "CentralAngle", "Displayer")]
        public PropertyDisplayer CentralAngleDisplayer
        {
            get { return angleDisplayer; }
            set { angleDisplayer = value; }
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName(null, "ArcLength", "Displayer")]
        public PropertyDisplayer ArcLengthDisplayer
        {
            get { return arclenDisplayer; }
            set { arclenDisplayer = value; }
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName(null, "ChordLength", "Displayer")]
        public PropertyDisplayer ChordLengthDisplayer
        {
            get { return chordlenDisplayer; }
            set { chordlenDisplayer = value; }
        }
        [Browsable(false)]
        public double Start
        {
            get { return (ske as PartialCircle).Start; }
        }
        [Browsable(false)]
        public double Sweep
        {
            get { return (ske as PartialCircle).Sweep; }
        }
        [Browsable(false)]
        public double PStart
        {
            get { return (pske as PartialEllipse).Start; }
        }
        [Browsable(false)]
        public double PSweep
        {
            get { return (pske as PartialEllipse).Sweep; }
        }
        [Browsable(false)]
        public abstract double NewStart { get; }
        [Browsable(false)]
        public virtual double NewSweep { get { return Sweep; } }
        [Browsable(false)]
        public abstract double NewPStart { get; }
        [Browsable(false)]
        public virtual double NewPSweep { get { return PSweep; } }
        [Browsable(false)]
        public double NewArcLength
        {
            get { return Math.Abs(NewSweep) * NewRadius; }
        }
        [Browsable(false)]
        public abstract double NewChordLength { get; }
        public override PointD[] GetTangentPoints(PointD passPoint)
        {
            return CurveTangent.GetArcTangentPoints(NewCenter, NewRadius, NewStart, NewSweep, passPoint);
        }
        public override void AddTracks()
        {
            track.Add(new KeyValuePair<PointD, double[]>(PCenter, new double[] { -Pad.Coordinate.RotateAngle.DegreeValue, pske.LongAxisHalfLength, pske.ShortAxisHalfLength, PStart * Core.Helper.Angle.RToD, PSweep * Core.Helper.Angle.RToD }));
        }
        public override PropertyDisplayer[] PropertyDisplayersCheckNearBy(PointD Plocation)
        {
            List<PropertyDisplayer> res = new List<PropertyDisplayer>(base.PropertyDisplayersCheckNearBy(Plocation));
            if (CentralAngleDisplayer.InRegion(Plocation))
            {
                res.Add(CentralAngleDisplayer);
            }
            if (ArcLengthDisplayer.InRegion(Plocation))
            {
                res.Add(ArcLengthDisplayer);
            }
            if (ChordLengthDisplayer.InRegion(Plocation))
            {
                res.Add(ChordLengthDisplayer);
            }
            return res.ToArray();
        }
        public override void ComponentChanged(ShapeBase component)
        {
            PartialCircle pc = ske as PartialCircle;
            PartialEllipse pe = pske as PartialEllipse;
            pc.Start = NewStart;
            pe.Start = NewPStart;
            pc.Sweep = NewSweep;
            pe.Sweep = NewPSweep;
            ChordLength = NewChordLength;
            ArcLength = NewArcLength;
            base.ComponentChanged(component);
            Pad.BuildArcSamples(ske.Curves[0], pske.Curves[0], Center, Radius, Start, Sweep);
        }
        public override void RefreshPropertyDisplayersText()
        {
            CentralAngleDisplayer.RefreshText();
            ArcLengthDisplayer.RefreshText();
            ChordLengthDisplayer.RefreshText();
            base.RefreshPropertyDisplayersText();
        }
        public override void RefreshPropertyDisplayersLocation()
        {
            CentralAngleDisplayer.RefreshLocation();
            ArcLengthDisplayer.RefreshLocation();
            ChordLengthDisplayer.RefreshLocation();
            base.RefreshPropertyDisplayersLocation();
        }
        public override void PaintProperties(Graphics gra)
        {
            if (ObjectState == ObjectState.Normal && Visible)
            {
                CentralAngleDisplayer.Paint(gra);
                ArcLengthDisplayer.Paint(gra);
                ChordLengthDisplayer.Paint(gra);
            }
            base.PaintProperties(gra);
        }
        public override void InternalPrepare(PointBase movePoint, ShapeBase sender = null)
        {
            foreach (PointBase item in OutChildren_Point)
            {
                ControlledOutPointsOriginalInfo.Add(item, new double[] { Utility.GetSweepRate(Start, Sweep, Center.GetAngle(item.ToPointD())) });
            }
            base.InternalPrepare(movePoint, sender);
        }
        public override PointD GetOutFreePointRecommendNewLocation(PointBase pt, bool getXY = true)
        {
            PointD xy = NewCenter.Offset(NewStart + NewSweep * ControlledOutPointsOriginalInfo[pt][0], NewRadius);
            return getXY ? xy : Pad.XYToPxy(xy);
        }
        public override void InternalClean(PointBase movedPoint, ShapeBase sender = null)
        {
            ControlledOutPointsOriginalInfo.Clear();
            base.InternalClean(movedPoint, sender);
        }
    }
}
